package oper

import (
	"context"
	"fmt"
	"net/url"
	"os"
	"strconv"
	"sync"

	"jgt-sdk/asapi"
	"jgt-sdk/utils"
)

var (
	internalHandle *Handle
	once           sync.Once
)

// InitOper 初始化运营服务
func InitOper(as *asapi.APIHandle) *Handle {
	once.Do(func() {
		internalHandle = &Handle{
			as:       as,
			identify: "OPER",
			lock:     new(sync.RWMutex),
		}
	})
	return internalHandle
}

// GetHandle 获取运营服务
func GetHandle() *Handle {
	return GetHandleWithTraceID("")
}

// GetHandleWithTraceID 获取运营服务
func GetHandleWithTraceID(traceID string) *Handle {
	if traceID == "" {
		traceID = utils.UUIDString()
	}
	handle := *internalHandle
	handle.traceID = traceID
	return &handle
}

// Handle 运营服务
type Handle struct {
	as       *asapi.APIHandle
	identify string
	host     string
	lock     *sync.RWMutex
	traceID  string
}

func (a *Handle) getHost() string {
	a.lock.RLock()
	host := a.host
	a.lock.RUnlock()
	if host == "" {
		a.lock.Lock()
		defer a.lock.Unlock()
		v, err := a.as.GetServiceHost(a.identify)
		if err == nil && v != "" {
			host = v
			a.host = v
		}
	}
	return host
}

func (a *Handle) getContext() context.Context {
	return utils.NewTraceIDContext(context.Background(), a.traceID)
}

// GetURL 获取URL
func (a *Handle) GetURL(router string) (string, error) {
	host := a.getHost()
	if host == "" {
		return "", fmt.Errorf("无效的Host")
	}
	return utils.RequestURL(host, router), nil
}

// AddUserRequest 增加用户请求参数
type AddUserRequest struct {
	RecordID     string `json:"record_id"`     // 记录ID
	Nickname     string `json:"nickname"`      // 昵称
	RealName     string `json:"real_name"`     // 真实姓名
	Photo        string `json:"photo"`         // 头像
	EnterpriseID string `json:"enterprise_id"` // 企业ID
	UserType     string `json:"user_type"`     // 用户类型编号
	Gender       int    `json:"gender"`        // 性别(1:男 2:女)
	Post         string `json:"post"`          // 岗位名称
	AuthStatus   int    `json:"auth_status"`   // 认证状态(1:已认证 2:未认证)
}

// AddUser 增加用户
func (a *Handle) AddUser(param *AddUserRequest) error {
	urlStr, err := a.GetURL("/srv/v1/users")
	if err != nil {
		return err
	}

	var result string
	err = utils.PostJSONWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, &result)
	if err != nil {
		return err
	} else if result == "ok" {
		return nil
	}

	return fmt.Errorf(result)
}

// GetUserReply 获取用户信息响应结果
type GetUserReply struct {
	UserID         string           `json:"user_id"`         // 记录ID
	Nickname       string           `json:"nickname"`        // 昵称
	RealName       string           `json:"real_name"`       // 真实姓名
	EnterpriseID   string           `json:"enterprise_id"`   // 企业ID
	EnterpriseName string           `json:"enterprise_name"` // 企业名称
	UserType       string           `json:"user_type"`       // 用户类型编号
	UserTypeName   string           `json:"user_type_name"`  // 用户类型名称
	Gender         int              `json:"gender"`          // 性别(1:男 2:女)
	Post           string           `json:"post"`            // 岗位名称
	Photo          string           `json:"photo"`           // 头像
	AuthStatus     int              `json:"auth_status"`     // 认证状态(1:已认证 2:未认证)
	Tel            string           `json:"tel"`             // 用户电话
	Settings       *UserSettingItem `json:"settings"`        // 用户设置项
}

// UserSettingItem 用户设置项
type UserSettingItem struct {
	IsSound     int `json:"is_sound"`     // 声音(1:开启 2:关闭)
	IsVibration int `json:"is_vibration"` // 振动(1:开启 2:关闭)
}

// GetUser 获取用户信息
func (a *Handle) GetUser(userID string, disable ...bool) (*GetUserReply, error) {
	cacheKey := fmt.Sprintf("c_oper_user_id_%s", userID)

	var cItem GetUserReply
	exists := a.as.GetCacheValue(cacheKey, &cItem, disable...)
	if exists {
		return &cItem, nil
	}

	urlStr, err := a.GetURL(fmt.Sprintf("/srv/v1/users/%s", userID))
	if err != nil {
		return nil, err
	}

	var result GetUserReply
	err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, nil, &result)
	if err != nil {
		return nil, err
	}

	a.as.SetCacheValue(cacheKey, result, 300)

	return &result, nil
}

// QuerySystemMenuReply 查询系统菜单响应数据
type QuerySystemMenuReply struct {
	RecordID  string                  `json:"record_id"`  // 记录内码
	Code      string                  `json:"code"`       // 菜单编号
	Name      string                  `json:"name"`       // 菜单名称
	Type      int                     `json:"type"`       // 菜单类型(10：系统 20：模块 30：功能 40：动作)
	Icon      string                  `json:"icon"`       // 菜单图标
	Router    string                  `json:"router"`     // 跳转路由
	LevelCode string                  `json:"level_code"` // 分级码
	ParentID  string                  `json:"parent_id"`  // 父级内码
	Children  []*QuerySystemMenuReply `json:"children"`   // 下级数据
}

// QuerySystemMenu 查询系统菜单
func (a *Handle) QuerySystemMenu(userType string, code string) ([]*QuerySystemMenuReply, error) {
	urlStr, err := a.GetURL("/srv/v1/users/menu")
	if err != nil {
		return nil, err
	}

	params := make(url.Values)
	params.Set("user_type", userType)
	params.Set("code", code)

	var result []*QuerySystemMenuReply
	err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, params, &result)
	if err != nil {
		return nil, err
	}

	return result, nil
}

// QueryCommonFunction 查询常用功能项
func (a *Handle) QueryCommonFunction(userID string) ([]*QuerySystemMenuReply, error) {
	urlStr, err := a.GetURL(fmt.Sprintf("/srv/v1/users/%s/function", userID))
	if err != nil {
		return nil, err
	}

	var result []*QuerySystemMenuReply
	err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, nil, &result)
	if err != nil {
		return nil, err
	}

	return result, nil
}

// GetEnterpriseReply 企业信息
type GetEnterpriseReply struct {
	Name         string `json:"name"`         // 企业名称
	Category     string `json:"category"`     // 行业类别
	Contacter    string `json:"contacter"`    // 企业联系人
	ContactTel   string `json:"contact_tel"`  // 联系电话
	Address      string `json:"address"`      // 企业地址
	EntryTime    int64  `json:"entry_time"`   // 入驻时间(时间戳)
	Logo         string `json:"logo"`         // 企业Logo
	Introduction string `json:"introduction"` // 企业简介
}

// GetEnterprise 获取企业信息
func (a *Handle) GetEnterprise(recordID string) (*GetEnterpriseReply, error) {
	urlStr, err := a.GetURL(fmt.Sprintf("/srv/v1/enterprises/%s", recordID))
	if err != nil {
		return nil, err
	}

	var result GetEnterpriseReply
	err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, nil, &result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

// UpdateEnterprisePanel 更新企业展板
func (a *Handle) UpdateEnterprisePanel(recordID string, isOpen int) error {
	urlStr, err := a.GetURL(fmt.Sprintf("/srv/v1/enterprises/%s/panel", recordID))
	if err != nil {
		return err
	}

	param := map[string]interface{}{
		"is_open": isOpen,
	}
	var result struct {
		Status string `json:"status"`
	}
	err = utils.PutJSONWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, &result)
	if err != nil {
		return err
	} else if result.Status == "ok" {
		return nil
	}

	return fmt.Errorf("服务器错误")
}

// GetParkReply 园区信息
type GetParkReply struct {
	RecordID     string  `json:"record_id"`     // 记录内码(uuid)
	Name         string  `json:"name"`          // 名称
	ParentID     string  `json:"parent_id"`     // 父级内码
	Type         int     `json:"type"`          // 园区类型（10:园区 20:区域 30:楼栋 40:单元 50:楼层 60门牌）
	SalesStatus  int     `json:"sales_status"`  // 销售状态(10:物业自用 20:物业自持 30:已售 40:待售)
	LeaseStatus  int     `json:"lease_status"`  // 租赁状态(10:已出租 20:待出租)
	BuildingArea float64 `json:"building_area"` // 建筑面积
	UsedArea     float64 `json:"used_area"`     // 使用面积
	LevelCode    string  `json:"level_code"`    // 分级码
}

// GetPark 获取园区建筑信息
func (a *Handle) GetPark(parkID string) (*GetParkReply, error) {
	urlStr, err := a.GetURL(fmt.Sprintf("/srv/v1/parks/%s", parkID))
	if err != nil {
		return nil, err
	}

	var result GetParkReply
	err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, nil, &result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

// AppLoginInitRequest 用户登录初始化请求参数
type AppLoginInitRequest struct {
	UserID     string `json:"user_id"`     // 用户ID
	Channel    string `json:"channel"`     // 渠道(android/ios)
	DeviceID   string `json:"device_id"`   // 设备ID
	DeviceType string `json:"device_type"` // 设备类型(iPhone/Android/iPad/Pad)
	NetType    string `json:"net_type"`    // 网络类型
	OS         string `json:"os"`          // 操作系统
	OSVersion  string `json:"os_version"`  // 操作系统版本
	PhoneBrand string `json:"phone_brand"` // 手机厂商
	PhoneModel string `json:"phone_model"` // 手机型号
}

// AppLoginInit 用户登录初始化
func (a *Handle) AppLoginInit(param *AppLoginInitRequest) error {
	urlStr, err := a.GetURL("/srv/v1/users/app_init")
	if err != nil {
		return err
	}

	var result string
	err = utils.PostJSONWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, &result)
	if err != nil {
		return err
	} else if result == "ok" {
		return nil
	}

	return fmt.Errorf(result)
}

// GetDictionaryReply 字典表返回信息
type GetDictionaryReply struct {
	Tree []map[string]interface{}
	Name string
	List []string
}

// GetDictionary 获取字典表返回信息
func (a *Handle) GetDictionary(ty, root string, level int, list ...string) (*GetDictionaryReply, error) {
	var (
		urlStr string
		err    error
		param  url.Values
		reply  = new(GetDictionaryReply)
	)
	urlStr, err = a.GetURL(fmt.Sprintf("srv/v1/dictionaries/%s", ty))
	switch ty {
	case "data":
		param["root"] = []string{root}
		param["level"] = []string{strconv.Itoa(level)}
		err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, &(reply.Tree))
	case "tree":
		param["root"] = []string{root}
		param["level"] = []string{strconv.Itoa(level)}
		err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, &(reply.Tree))
	case "list":
		param["root"] = []string{root}
		param["code"] = list
		err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, &(reply.List))
	case "one":
		param["code"] = []string{root}
		err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, &(reply.Name))
	default:
		return nil, fmt.Errorf("未知查询类型")
	}
	return reply, err

}

// WriteOff 用户注销
func (a *Handle) WriteOff(userID string) error {
	urlStr, err := a.GetURL(fmt.Sprintf("/srv/v1/users/%s/writeoff", userID))
	if err != nil {
		return err
	}

	var result string
	err = utils.PostJSONWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, nil, &result)
	if err != nil {
		return err
	} else if result == "ok" {
		return nil
	}

	return fmt.Errorf(result)
}

// GetSystemParameter 获取系统参数
func (a *Handle) GetSystemParameter(code string) (utils.S, error) {
	ckey := fmt.Sprintf("system_parameter_%s", code)

	var cItem struct {
		Value utils.S
	}
	exists := a.as.GetCacheValue(ckey, &cItem)
	if exists {
		return cItem.Value, nil
	}

	urlStr, err := a.GetURL(fmt.Sprintf("/srv/v1/system_parameters/%s", code))
	if err != nil {
		return "", err
	}

	var result struct {
		Value string `json:"value"`
	}
	err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, nil, &result)
	if err != nil {
		return "", err
	}

	value := utils.S(result.Value)
	cItem.Value = value
	a.as.SetCacheValue(ckey, cItem, 300)
	return value, nil
}

// DefaultSystemParameter 获取系统参数，没有则返回默认值
func (a *Handle) DefaultSystemParameter(code string, defaultValue string) utils.S {
	val, err := a.GetSystemParameter(code)
	if err != nil || val.String() == "" {
		if err != nil {
			os.Stdout.WriteString("[warn] 获取系统参数发生错误：" + err.Error())
		}
		return utils.S(defaultValue)
	}
	return val
}

type UserShow struct {
	RecordID string `json:"record_id"`
}

// SearchUserIdByName 根据用户名查询可能的用户ID
func (a *Handle) SearchUserIdByName(name string) ([]string, error) {
	var (
		urlStr string
		data   []*UserShow
		err    error
		result []string
	)
	urlStr, err = a.GetURL(fmt.Sprintf("/srv/v1/users/search/%s", name))
	if err != nil {
		return nil, err
	}

	err = utils.GetWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, nil, &result)
	if err != nil {
		return nil, err
	}

	for _, v := range data {
		result = append(result, v.RecordID)
	}

	return result, nil
}
